/*
 * Copyright (C) 2009, Edmundo Albuquerque de Souza e Silva.
 *
 * This file may be distributed under the terms of the Q Public License
 * as defined by Trolltech AS of Norway and appearing in the file
 * LICENSE.QPL included in the packaging of this file.
 *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

package net.sf.fmj.ui.application;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import javax.media.protocol.ContentDescriptor;

import net.sf.fmj.ui.wizards.ProcessorWizardConfig;
import net.sf.fmj.ui.wizards.RTPTransmitWizardConfig;
import net.sf.fmj.ui.wizards.TrackConfig;
import net.sf.fmj.ui.wizards.TranscodeWizardConfig;
import net.sf.fmj.utility.LoggerSingleton;
import net.sf.fmj.utility.SerializationUtils;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * 
 * 
 *
 */
public class PlayerPanelPrefs
{
	private static final Logger logger = LoggerSingleton.logger;

	/** versio of the xml file format */
	private static final String version = "0.1";

	
	public List recentUrls = new ArrayList();
	public boolean autoPlay = true;
	public boolean autoLoop = false;
	
	public RTPTransmitWizardConfig rtpTransmitWizardConfig = new RTPTransmitWizardConfig();
	public TranscodeWizardConfig transcodeWizardConfig = new TranscodeWizardConfig();
	
	public static File getFile() 
	{
		/** the name of the file used to store the prefs */
		final String filename = ".fmjstudio.prefs.xml"; 

		String home = System.getProperty("user.home");
		return new File(home + File.separator + filename);
	}
	
	/* ---------------------- XML operations --------------------- */

	private static final String ELEMENT_REGISTRY = "fmj-studio-prefs";
	private static final String ATTR_VERSION = "version";
	
	private static final String ELEMENT_RECENT_URLS = "recent-urls";	
	private static final String ELEMENT_RECENT_URL = "url";

	private static final String ELEMENT_RTP_TRANSMIT_WIZARD_CONFIG = "rtp-transmit-wizard-config";	
	private static final String ELEMENT_TRANSCODE_WIZARD_CONFIG = "transcode-wizard-config";
	
	/**
	 * Load the Registry data from a Reader/
	 */
	public void load(Reader reader) throws IOException 
	{
		
		// read the registry
		try 
		{
			SAXBuilder saxBuilder = new SAXBuilder();
			Document document = saxBuilder.build(reader);
			
			// read all the data from the document and place into data structures.
			loadDocument(document);
		}
		catch (JDOMException e) 
		{
			// problem parsing XML.
			throw new IOException(e.getMessage());
		}
	}
	
	/**
	 * Write the registry data to the Writer.
	 * 
	 * @param writer destination for the registry data.
	 * @throws IOException
	 */
	public void write(Writer writer) throws IOException 
	{
		// build document from registry data structures
		Document document = buildDocument();
		
		XMLOutputter xmlOutputter = new XMLOutputter();
		xmlOutputter.setFormat(Format.getPrettyFormat());

		xmlOutputter.output(document, writer);
	}
	

	private void loadDocument(Document document) throws IOException 
	{
		
		Element rootElement = document.getRootElement();
		String versionString = rootElement.getAttributeValue(ATTR_VERSION);
		
		// TODO use version String
		logger.info("FMJStudio preferences document version " + versionString);
		
		Element element_RecentUrls = rootElement.getChild(ELEMENT_RECENT_URLS);
		parseElement_RecentUrls(element_RecentUrls);
		
		// auto-start
		{
			Element e = rootElement.getChild("auto-play");
			if (e != null)
				autoPlay = e.getTextTrim().equals("" + true);
		}
		
		// auto-loop
		{
			Element e = rootElement.getChild("auto-loop");
			if (e != null)
				autoLoop = e.getTextTrim().equals("" + true);
		}
		
		parseElement_RTPTransmitWizardConfig(rootElement.getChild(ELEMENT_RTP_TRANSMIT_WIZARD_CONFIG));
		parseElement_TranscodeWizardConfig(rootElement.getChild(ELEMENT_TRANSCODE_WIZARD_CONFIG));
	}

	/**
	 * Builds a Document from the registry data structures.
	 * 
	 * @return the Document.
	 * @throws IOException 
	 */
	private Document buildDocument() throws IOException 
	{
		Document document = new Document();
		
		Element rootElement = new Element(ELEMENT_REGISTRY);
		rootElement.setAttribute(ATTR_VERSION, version);
		
		document.setRootElement(rootElement);

		rootElement.addContent(buildElement_RecentUrls());
		
		// auto-start
		{
			Element e = new Element("auto-play");
			e.setText("" + autoPlay);
			rootElement.addContent(e);
		}
		// auto-loop
		{
			Element e = new Element("auto-loop");
			e.setText("" + autoLoop);
			rootElement.addContent(e);
		}
		
		rootElement.addContent(buildElement_RTPTransmitWizardConfig());
		rootElement.addContent(buildElement_TranscodeWizardConfig());
		
		
		return document;
	}
	

	private void parseElement_RecentUrls(Element element) {
		recentUrls.clear();
		List list = element.getChildren(ELEMENT_RECENT_URL);
		for (int i=0; i<list.size(); i++) 
		{
			Element stringElement = (Element) list.get(i);
			recentUrls.add(stringElement.getTextTrim());
		}
	}
	
	private Element buildElement_RecentUrls() 
	{
		Element element = new Element(ELEMENT_RECENT_URLS);
		
		Iterator iterator = recentUrls.iterator();
		while (iterator.hasNext()) 
		{
			String s = (String) iterator.next();
			Element element_RecentUrl = new Element(ELEMENT_RECENT_URL);
			element_RecentUrl.setText(s);
			element.addContent(element_RecentUrl);
		}

		return element;
	}
	
	private static void parseElement_ProcessorWizardConfig(Element element, ProcessorWizardConfig processorWizardConfig) 
	{
		
		{
			final Element e = element.getChild("source-url");
			if (e != null)
				processorWizardConfig.url = e.getTextTrim();
		}

		{
			final Element e = element.getChild("content-descriptor-encoding");
			if (e != null)
				processorWizardConfig.contentDescriptor = new ContentDescriptor(e.getTextTrim());
		}

		
		
		{
			final Element e = element.getChild("track-configs");
			if (e != null)
			{
				final List trackConfigElements = e.getChildren("track-config");
				final TrackConfig[] trackConfigs = new TrackConfig[trackConfigElements.size()];
				for (int j = 0; j < trackConfigElements.size(); ++j) 
				{
					trackConfigs[j] = new TrackConfig();
					
					final Element e2 = (Element) trackConfigElements.get(j);
					
					// enabled
					{
						final Element e3 = e2.getChild("enabled");
						if (e3 != null)
						{
							trackConfigs[j].enabled = e3.getTextTrim().equals("" + true);
						}
					}
					
					// format:
					{
						final Element e3 = e2.getChild("format");
						if (e3 != null)
						{
							try
							{
								trackConfigs[j].format = SerializationUtils.deserialize(e3.getTextTrim());
							} catch (IOException e1)
							{
								logger.warning("Unable to deserialize format: " + e3.getTextTrim() + ": " + e1);
							} catch (ClassNotFoundException e1)
							{
								logger.warning("Unable to deserialize format: " + e3.getTextTrim() + ": " + e1);
							}
						}
					}
					
				}
			}
		}
		
		{
			final Element e = element.getChild("dest-url");
			if (e != null)
			{
				final String destUrlStr = e.getTextTrim();
				processorWizardConfig.destUrl = destUrlStr;
//				try
//				{
//					
//					rtpTransmitWizardConfig.destUrl = RTPUrlParser.parse(destUrlStr);
//				} catch (RTPUrlParserException ex)
//				{
//					logger.warning("Unable to parse RTP URL: " + destUrlStr + ": " + e);
//					
//				}
			}
		}
		
	}
	
	private void parseElement_RTPTransmitWizardConfig(Element element) 
	{
		rtpTransmitWizardConfig = new RTPTransmitWizardConfig();
		if (element != null)
			parseElement_ProcessorWizardConfig(element, rtpTransmitWizardConfig);
	}
	
	private void parseElement_TranscodeWizardConfig(Element element)
	{
		transcodeWizardConfig = new TranscodeWizardConfig();
		if (element != null)
			parseElement_ProcessorWizardConfig(element, transcodeWizardConfig);
	}
	
	private static Element buildElement_ProcessorWizardConfig(ProcessorWizardConfig processorWizardConfig, String elementStr) 
	{
		Element element = new Element(elementStr);
		
		if (processorWizardConfig.url != null)
		{
			final Element e = new Element("source-url");
			e.setText(processorWizardConfig.url);
			element.addContent(e);
		}

		if (processorWizardConfig.contentDescriptor != null)
		{
			final Element e = new Element("content-descriptor-encoding");
			e.setText(processorWizardConfig.contentDescriptor.getEncoding());
			element.addContent(e);
			
		}
		
		if (processorWizardConfig.trackConfigs != null)
		{
			
			final Element e = new Element("track-configs");
			element.addContent(e);
			for (int i = 0; i < processorWizardConfig.trackConfigs.length; ++i)
			{
				final TrackConfig trackConfig = processorWizardConfig.trackConfigs[i];
				
				final Element e2 = new Element("track-config");
				e.addContent(e2);
				
				// enabled:
				{
					final Element e3 = new Element("enabled");
					e2.addContent(e3);
					e3.setText("" + trackConfig.enabled);
				}
				
				// format:
				if (trackConfig.format != null)
				{
					final Element e3 = new Element("format-serialized");
					try
					{
						e3.setText(SerializationUtils.serialize(trackConfig.format));
						e2.addContent(e3);
					} catch (IOException e1)
					{
						logger.warning("Unable to serialize format: " + trackConfig.format + ": " + e);
					}
					
				}
				
			}
		}
		
		if (processorWizardConfig.destUrl != null)
		{
			final Element e = new Element("dest-url");
			e.setText(processorWizardConfig.destUrl.toString());
			element.addContent(e);
		}
		
		return element;
	}

	private Element buildElement_RTPTransmitWizardConfig() 
	{
		return buildElement_ProcessorWizardConfig(rtpTransmitWizardConfig, ELEMENT_RTP_TRANSMIT_WIZARD_CONFIG);
	}
	
	private Element buildElement_TranscodeWizardConfig() 
	{
		return buildElement_ProcessorWizardConfig(transcodeWizardConfig, ELEMENT_TRANSCODE_WIZARD_CONFIG);
	}
}
